﻿/*=============================================================================
  Copyright (C) 2012 - 2016 Allied Vision Technologies.  All Rights Reserved.

  Redistribution of this file, in original or modified form, without
  prior written consent of Allied Vision Technologies is prohibited.

  -------------------------------------------------------------------------------

  File:        ApiController.cpp

  Description: Implementation file for the ApiController helper class that
  demonstrates how to implement an asynchronous, continuous image
  acquisition with VimbaCPP.

  -------------------------------------------------------------------------------

  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE,
  NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR  PURPOSE ARE
  DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  =============================================================================*/

#include "VimbaApi/ApiController.h"
#include <sstream>
#include <iostream>
#include "Common/StreamSystemInfo.h"
#include "Common/ErrorCodeToMessage.h"
#include <QDebug>
#include <QThread>
namespace AVT {
namespace VmbAPI {
namespace Examples {

enum    { NUM_FRAMES = 3, };

ApiController::ApiController()
// Get a reference to the Vimba singleton
    : m_system(VimbaSystem::GetInstance())
{
}

ApiController::~ApiController()
{
    m_system.Shutdown();
}

std::string ApiController::ErrorCodeToMessage(VmbErrorType eErr) const
{
    return AVT::VmbAPI::Examples::ErrorCodeToMessage(eErr);
}

VmbErrorType ApiController::StartUp()
{
    VmbErrorType res;

    // Start Vimba
    res = m_system.Startup();
    if (VmbErrorSuccess == res)
    {
        // This will be wrapped in a shared_ptr so we don't delete it
        SP_SET(m_pCameraObserver, new CameraObserver());
        SP_SET(m_pFrameObserver, new FrameObserver(m_pCamera));
        // Register an observer whose callback routine gets triggered whenever a camera is plugged in or out
        res = m_system.RegisterCameraListObserver(m_pCameraObserver);
    }

    return res;
}

void ApiController::ShutDown()
{
    // Release Vimba
    m_system.Shutdown();
}

VmbErrorType ApiController::GetFeatureIntValue(const std::string &featureName, VmbInt64_t & value)
{
    if (SP_ISNULL(m_pCamera))
    {
        return VmbErrorBadParameter;
    }
    FeaturePtr      pFeature;
    VmbErrorType    result;
    result = SP_ACCESS(m_pCamera)->GetFeatureByName(featureName.c_str(), pFeature);
    if (VmbErrorSuccess == result)
    {
        result = SP_ACCESS(pFeature)->GetValue(value);
    }
    return result;
}

VmbErrorType ApiController::SetFeatureIntValue(const std::string &featureName, VmbInt64_t value)
{
    if (SP_ISNULL(m_pCamera))
    {
        return VmbErrorBadParameter;
    }
    FeaturePtr      pFeature;
    VmbErrorType    result;
    result = SP_ACCESS(m_pCamera)->GetFeatureByName(featureName.c_str(), pFeature);
    if (VmbErrorSuccess == result)
    {
        result = SP_ACCESS(pFeature)->SetValue(value);
    }
    return result;
}

VmbErrorType ApiController::GetFeatureDoubleValue(const std::string &featureName, double & value){
    if (SP_ISNULL(m_pCamera))
    {
        return VmbErrorBadParameter;
    }
    FeaturePtr      pFeature;
    VmbErrorType    result;
    result = SP_ACCESS(m_pCamera)->GetFeatureByName(featureName.c_str(), pFeature);
    if (VmbErrorSuccess == result)
    {
        result = SP_ACCESS(pFeature)->GetValue(value);
    }
    return result;
}

VmbErrorType ApiController::SetFeatureDoubleValue(const std::string &featureName, double value){
    if (SP_ISNULL(m_pCamera))
    {
        return VmbErrorBadParameter;
    }
    FeaturePtr      pFeature;
    VmbErrorType    result;
    result = SP_ACCESS(m_pCamera)->GetFeatureByName(featureName.c_str(), pFeature);
    if (VmbErrorSuccess == result)
    {
        result = SP_ACCESS(pFeature)->SetValue(value);
    }
    return result;
}

VmbErrorType ApiController::StartContinuousImageAcquisition()
{
    VmbErrorType res;
    if (m_bCamera)
    {
        //// Set the GeV packet size to the highest possible value
        //// (In this example we do not test whether this cam actually is a GigE cam)
        FeaturePtr pCommandFeature;
        if (VmbErrorSuccess == SP_ACCESS(m_pCamera)->GetFeatureByName("GVSPAdjustPacketSize", pCommandFeature))
        {
            if (VmbErrorSuccess == SP_ACCESS(pCommandFeature)->RunCommand())
            {
                bool bIsCommandDone = false;
                do
                {
                    if (VmbErrorSuccess != SP_ACCESS(pCommandFeature)->IsCommandDone(bIsCommandDone))
                    {
                        break;
                    }
                } while (false == bIsCommandDone);
            }
        }
        SetInternalMode(m_nCameraMode);
        if (VmbErrorSuccess == res)
        {
            // Store currently selected image format
            FeaturePtr pFormatFeature;
            res = SP_ACCESS(m_pCamera)->GetFeatureByName("PixelFormat", pFormatFeature);
            if (VmbErrorSuccess == res)
            {
                res = SP_ACCESS(pFormatFeature)->GetValue(m_nPixelFormat);
                if (VmbErrorSuccess == res)
                {
                    // Start streaming
                    res = SP_ACCESS(m_pCamera)->StartContinuousImageAcquisition(NUM_FRAMES, m_pFrameObserver);
                }
            }
        }
        if (VmbErrorSuccess != res)
        {
            // If anything fails after opening the camera we close it
//            SP_ACCESS(m_pCamera)->Close();
        }
    }

    return res;
}

VmbErrorType ApiController::StopContinuousImageAcquisition()
{
    // Stop streaming
    VmbErrorType res = SP_ACCESS(m_pCamera)->StopContinuousImageAcquisition();
    // Close camera
    ClearFrameQueue();
    return res;
}

CameraPtrVector ApiController::GetCameraList()
{
    CameraPtrVector cameras;
    // Get all known cameras
    if (VmbErrorSuccess == m_system.GetCameras(cameras))
    {
        // And return them
        return cameras;
    }
    return CameraPtrVector();
}

int ApiController::GetWidth()
{
    GetFeatureIntValue("Width",m_nWidth);
    return static_cast<int>(m_nWidth);
}

int ApiController::GetHeight()
{
    GetFeatureIntValue("Height",m_nHeight);
    return static_cast<int>(m_nHeight);
}

VmbPixelFormatType ApiController::GetPixelFormat() const
{
    return static_cast<VmbPixelFormatType>(m_nPixelFormat);
}

FramePtr ApiController::GetFrame()
{
    return SP_DYN_CAST(m_pFrameObserver, FrameObserver)->GetFrame();
}

void ApiController::ClearFrameQueue()
{
    SP_DYN_CAST(m_pFrameObserver, FrameObserver)->ClearFrameQueue();
}

VmbErrorType ApiController::QueueFrame(FramePtr pFrame)
{
    return SP_ACCESS(m_pCamera)->QueueFrame(pFrame);
}

QObject* ApiController::GetCameraObserver()
{
    return SP_DYN_CAST(m_pCameraObserver, CameraObserver).get();
}

QObject* ApiController::GetFrameObserver()
{
    return SP_DYN_CAST(m_pFrameObserver, FrameObserver).get();
}

std::string ApiController::GetVersion() const
{
    std::ostringstream os;
    os << m_system;
    return os.str();
}

VmbErrorType ApiController::OpenCameraF(const std::string &rStrCameraID)
{
    VmbErrorType res;
    if (NULL == m_pCamera)
    {
        res = m_system.OpenCameraByID(rStrCameraID.c_str(), VmbAccessModeFull, m_pCamera);
        if (VmbErrorSuccess == res)
        {
            m_bCamera = true;
        }
    }
    return res;
}

void ApiController::CloseCamerF()
{
    m_pCamera->Close();
}

bool ApiController::SetInternalMode(int mode)
{
    if (SP_ISNULL(m_pCamera))
    {
        return false;
    }

    FeaturePtr feature;
    std::string lineMode;
    switch (mode)
    {

    case 0:
        /// setting trigger type to ExposureStart
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSelector", feature);
        feature->SetValue("FrameStart");
        /// Select Line1
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSource", feature);
        feature->SetValue("Line1");
        /// configuring rising edge trigger
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerActivation", feature);
        feature->SetValue("RisingEdge");
        /// setting TriggerMode to On
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerMode", feature);
        feature->SetValue("On");
        break;

    case 1:
        /// setting trigger type to ExposureStart
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSelector", feature);
        feature->SetValue("FrameStart");
        /// Select Line1
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSource", feature);
        feature->SetValue("Software");
        /// configuring rising edge trigger
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerActivation", feature);
        feature->SetValue("RisingEdge");
        /// setting TriggerMode to On
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerMode", feature);
        feature->SetValue("On");
        break;

    case 2:
    default:
        /// setting trigger type to ExposureStart
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSelector", feature);
        feature->SetValue("FrameStart");
        /// Select Line1
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerSource", feature);
        feature->SetValue("Freerun");
        /// configuring rising edge trigger
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerActivation", feature);
        feature->SetValue("RisingEdge");
        /// setting TriggerMode to On
        SP_ACCESS(m_pCamera)->GetFeatureByName("TriggerMode", feature);
        feature->SetValue("On");
        break;
    }
    return true;
}

}
}
} // namespace AVT::VmbAPI::Examples
